
package com.scs.application.modules.base.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.msg.provider.ISceneMsgPushProvider;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.MaterialApplicantAddBatchDto;
import com.scs.application.modules.base.entity.*;
import com.scs.application.modules.base.mapper.MaterialApplicantMapper;
import com.scs.application.modules.base.request.MaterialApplicantItemQueryRequest;
import com.scs.application.modules.base.request.MaterialApplicantQueryRequest;
import com.scs.application.modules.base.service.*;
import com.scs.application.modules.cert.entity.CertificateRepository;
import com.scs.application.modules.cert.request.CertificateRepositoryQueryRequest;
import com.scs.application.modules.cert.service.CertificateRepositoryService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * MaterialApplicant service 实现
 */
@Slf4j
@AllArgsConstructor
@Service
public class MaterialApplicantServiceImpl extends BaseServiceImpl<MaterialApplicantMapper, MaterialApplicant> implements MaterialApplicantService {

    private final HospitalMaterialService hospitalMaterialService;

    private final MaterialApplicantItemService materialApplicantItemService;

    private final HospitalService hospitalService;

    private final MaterialSpecService materialSpecService;

    private final MaterialService materialService;

    private final ISceneMsgPushProvider ISceneMsgPushProvider;

    private final SupplierService supplierService;

    private final ManufacturerService manufacturerService;

    private final CertificateRepositoryService certificateRepositoryService;

    private final ApplicantCertificateRecordService applicantCertificateRecordService;
    private final MaterialCatalogService materialCatalogService;


    @Override
    public boolean removeCascadeById(Serializable id) {
        materialApplicantItemService.remove(Wrappers.<MaterialApplicantItem>query().eq("applicant_id", id));
        return super.removeById(id);
    }

    @Override
    public List<MaterialApplicant> list(MaterialApplicantQueryRequest request) {
        List<MaterialApplicant> list = this.list(Wrappers.<MaterialApplicant>query()
                .eq(request.getHospitalId() != null, "hospital_id", request.getHospitalId())
                .eq(request.getSupplierId() != null, "supplier_id", request.getSupplierId())
                .like(StringUtils.isNotBlank(request.getCode()), "code", request.getCode())
                .eq(request.getStatus() != null, "status", request.getStatus())
                .orderByDesc("code")
        );
        return list;
    }

    @Override
    public IPage<MaterialApplicant> page(MaterialApplicantQueryRequest request) {
        request.setSupplierId(UserUtils.getSupplierId());
        return this.baseMapper.page(request.getPage(), request);
    }

    @Override
    public IPage<MaterialApplicant> pageAudit(MaterialApplicantQueryRequest request) {
        request.setHospitalId(UserUtils.getHospitalId());
        return this.baseMapper.page(request.getPage(), request);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveHospital(MaterialApplicant entity) {

        //供应商id，单据号，单据状态，医院id
        entity.setSupplierId(UserUtils.getSupplierId())
                .setCode(SerialUtils.generateCode(
                        SerialRuleConsts.BASE_MATERIAL_APPLICANT_CODE, SerialOwnerUtils.getSupplierOwner(entity.getSupplierId())))
                .setStatus(MaterialApplicant.STATUS_UNSUBMIT);
        return this.save(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submit(String id) {

        MaterialApplicant ma = this.getById(id);
        if (ma == null) {
            return;
        }
        //当前状态是否为制单状态
        if (ma.getStatus() != MaterialApplicant.STATUS_UNSUBMIT) {
            throw new BusinessException("当前状态不是制单状态");
        }

        //商品明细是否为空
        List<MaterialApplicantItem> list = materialApplicantItemService.list(Wrappers.<MaterialApplicantItem>query()
                .eq("applicant_id", id));

        if (list.isEmpty()) {
            throw new BusinessException("明细行为空，不允许提交");
        }

        //医院商品表中是否已存在
        for (MaterialApplicantItem materialApplicantItem : list) {
            assertRelExist(ma.getHospitalId(), materialApplicantItem.getMaterialSpecId());

            if (UtilCommon.strIsNull(materialApplicantItem.getBidno()) && !"无".equals(materialApplicantItem.getBidno())) {
                Material material = materialService.getById(materialApplicantItem.getMaterialId());
                BusinessException.throwErrorIf(material== null,"商品不存在，请重新发起申请");
                BusinessException.throwError("请填写中标号,商品[{}]，没有中标号的话请填无",material.getMaterialName());
            }
        }

        //修改状态为提交待审核
        MaterialApplicant materialApplicant = new MaterialApplicant();
        materialApplicant.setStatus(MaterialApplicant.STATUS_SUBMITED).setId(ma.getId());
        this.updateById(materialApplicant);

        // 添加资质信息到资质记录表
        CertificateRepositoryQueryRequest request = new CertificateRepositoryQueryRequest();
        List<String> materialIds = list.stream().map(o -> o.getMaterialId()).distinct().collect(Collectors.toList());
        request.setSupplierId(UserUtils.getSupplierId()).setTargetIds(materialIds);
        // 获取商品关联的资质
        List<CertificateRepository> certificateRepositories = certificateRepositoryService.pageForAudit(request);
        List<ApplicantCertificateRecord> acrList = BeanUtils.copyProperties(certificateRepositories, ApplicantCertificateRecord.class);
        acrList.stream().forEach(o -> o.setApplicantType("MA").setApplicantId(ma.getId()).setId(null));
        applicantCertificateRecordService.saveBatch(acrList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pass(String id) {

        MaterialApplicant ma = this.getById(id);
        if (ma == null) {
            return;
        }

        // 当前状态是否为提交待审核
        if (ma.getStatus() != MaterialApplicant.STATUS_SUBMITED) {
            throw new BusinessException("当前状态不是待审核状态");
        }

        // 修改申请单状态为通过
        MaterialApplicant materialApplicant = new MaterialApplicant();
        materialApplicant.setStatus(MaterialApplicant.STATUS_PASSED)
                .setAuditor(UserUtils.getHospital().getName())
                .setGmtAudited(new Date())
                .setId(ma.getId());
        this.updateById(materialApplicant);


        // 医院商品表中是否已存在
        List<MaterialApplicantItem> list = materialApplicantItemService.list(new MaterialApplicantItemQueryRequest().setApplicantId(id));

        // 向医院商品插入数据
        List<HospitalMaterial> hms = Lists.newArrayListWithCapacity(list.size());
        HospitalMaterial hm;
        Hospital hospital = hospitalService.getById(ma.getHospitalId());

        for (MaterialApplicantItem item : list) {
            hm = hospitalMaterialService.getOne(
                    Wrappers.<HospitalMaterial>query()
                            .eq("hospital_id", ma.getHospitalId())
                            .eq("material_spec_id", item.getMaterialSpecId())
            );

            if (hm != null) {//医院商品表中已存在
                /*hm.setInactive(HospitalMaterial.ACTIVATE);
                hms.add(hm);*/
                continue;
            }

            //医院商品表中不存在
            MaterialSpec materialSpec = materialSpecService.getById(item.getMaterialSpecId());
            Material material = materialService.getById(item.getMaterialId());
            Manufacturer manufacturer = manufacturerService.getById(material.getManufacturerId());
            MaterialCatalog materialCatalog = materialCatalogService.getById(material.getCatalogId());
            Supplier supplier = supplierService.getById(material.getSupplierId());
            if (materialCatalog == null) {
                materialCatalog = new MaterialCatalog();
            }
            if (supplier == null) {
                supplier = new Supplier();
            }
            hm = new HospitalMaterial();

           /* hm = new HospitalMaterial();
            Material material = materialService.getById(item.getMaterialId());
            MaterialSpec materialSpec = materialSpecService.getById(item.getMaterialSpecId());
            Manufacturer manufacturer = manufacturerService.getById(material.getManufacturerId());

            if (material == null || materialSpec == null) {
                throw new BusinessException("商品不存在");
            }

            BeanUtils.copyProperties(materialSpec, hm);

            if (manufacturer != null) {
                hm.setManufacturerId(material.getManufacturerId())
                        .setManufacturerName(manufacturer.getName());
            }

            hm.setHospitalId(ma.getHospitalId())
                    .setMaterialId(item.getMaterialId())
                    .setMaterialSpecId(item.getMaterialSpecId())
                    .setMaterialSpec(item.getMaterialSpec())
                    .setMaterialName(material.getMaterialName())
                    .setMaterialCode(SerialUtils.generateCode(SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE, SerialOwnerUtils.getSupplierOwner(ma.getSupplierId())))
                    .setHospitalName(hospital.getName())
                    .setMaterialTradeName(material.getMaterialTradeName())
                    .setMiniumRequestQty(0.0)
                    .setCertificateNo(material.getCertificateNo())
                    .setInactive(HospitalMaterial.DEACTIVATE)
                    .setId(null);

            hms.add(hm);*/
            BeanUtils.copyProperties(item, hm);
            hm.setHospitalId(ma.getHospitalId())
                    .setMaterialCode(SerialUtils.generateCode(SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE, SerialOwnerUtils.getHospitalOwner(ma.getHospitalId())))
                    .setHospitalName(hospital.getName())
                    .setMiniumRequestUnit(null)
                    .setMiniumRequestQty(0.0)
                    .setManufacturerId(material.getManufacturerId())
                    .setManufacturerName(manufacturer.getName())
                    .setInactive(HospitalMaterial.ACTIVATE)
                    .setCatalogId(material.getCatalogId()).setCatalogName(materialCatalog.getName())
                    .setManufacturerId(manufacturer.getId()).setManufacturerName(manufacturer.getName())
                    .setSupplierId(material.getSupplierId()).setSupplierName(supplier.getName())
            ;

            // 注册证信息
            hm.setCertificateNo(material.getCertificateNo())
                    .setCertificateExpiredDate(material.getCertificateExpiredDate())
                    .setCertificateExpiredStartDate(material.getCertificateExpiredStartDate());
            hm.setBidno(item.getBidno());

            // 规格信息及单位
            hm
                .setIsOneThingOneYard(materialSpec.getIsOneThingOneYard())
                .setIsConsignment(materialSpec.getIsConsignment())
                .setOrderQty(materialSpec.getOrderQty())
                .setOrderUnit(materialSpec.getOrderUnit())
                .setMaterialErpCode(materialSpec.getMaterialErpCode())
                .setMaterialSpec(materialSpec.getMaterialSpec())
            ;

            // 医保信息
            hm.setHisMedicareNo(material.getHisMedicareNo()).setHisMedicareName(material.getHisMedicareName())
            .setHisMedicareNo2(material.getHisMedicareNo2()).setHisMedicareName2(material.getHisMedicareName2());

            hms.add(hm);

        }

        if (hms.size() == 0) {
            throw new BusinessException("供货关系均已存在");
        }

        /** 批量生成编码 */
        List<String> codes = SerialUtils.batchGenerateCode(
                SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE, SerialOwnerUtils.getHospitalOwner(ma.getHospitalId()), hms.size());
        AtomicInteger codeIndex = new AtomicInteger(0);
        hms.stream().forEach(o -> o.setMaterialCode(codes.get(codeIndex.getAndIncrement())));

        // 批量保存
        hospitalMaterialService.saveOrUpdateBatch(hms);

        //发送审核消息给供应商
//        Supplier supplier = supplierService.getById(ma.getSupplierId());

        /*HashMap<String, Object> params = Maps.newHashMap();
        params.put("hospital_name", hospital.getName());
        params.put("code", ma.getCode());
        params.put("send_date", DateUtils.format(new Date(), "yyyy-MM-dd"));*/

//        SceneMessage message = new SceneMessage();
//        message.setSceneCode(MsgConsts.SCENE_MATERIAL_APPLICANT_SUCCESS).setReceiver(supplier.getLoginKey())
//                .setReceiverType(ReceiverType.USER);
//        message.addParam("first", "你好,你的供货申请已通过", MessageType.WECHAT)
//                .addParam("keyword1", hospital.getName(), MessageType.WECHAT)
//                .addParam("keyword2", DateUtils.format(new Date(), "yyyy-MM-dd"), MessageType.WECHAT)
//                .addParam("keyword3", "审核通过", MessageType.WECHAT)
//                .addParam("remark", "申请单号：" + ma.getCode(), MessageType.WECHAT);
//
//        ISceneMsgPushProvider.push(message);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancel(String id, String reason) {

        MaterialApplicant ma = this.getById(id);
        if (ma == null) {
            return;
        }

        //当前状态是否为提交待审核
        if (ma.getStatus() != MaterialApplicant.STATUS_SUBMITED) {
            throw new BusinessException("当前状态不是待审核状态");
        }

        //修改申请单状态为已取消，并提交
        MaterialApplicant materialApplicant = new MaterialApplicant();
        materialApplicant.setStatus(MaterialApplicant.STATUS_CANCELED)
                .setAuditedRemark(reason)
                .setAuditor(UserUtils.getHospital().getName())
                .setGmtAudited(new Date())
                .setId(ma.getId());
        this.updateById(materialApplicant);

        applicantCertificateRecordService.remove(Wrappers.<ApplicantCertificateRecord>query()
                .eq(StringUtils.isNotBlank(id), "applicant_id", id));
    }


    @Override
    public void assertRelExist(String hospitalId, String materialSpecId) {
        //关系表中是否存在
        HospitalMaterial one = hospitalMaterialService.getOne(
                Wrappers.<HospitalMaterial>query()
                        .eq("hospital_id", hospitalId)
                        .eq("material_spec_id", materialSpecId)
                        .eq("inactive", HospitalMaterial.ACTIVATE)
        );
        if (one == null) {
            return;
        }
        Hospital h = hospitalService.getById(hospitalId);
        MaterialSpec ms = materialSpecService.getById(materialSpecId);
        throw new BusinessException(h.getName() + "已存在" + ms.getMaterialSpec() + "了！");
    }




    private void fillData(MaterialApplicant entity) {
        Hospital hospital =  hospitalService.getById(entity.getHospitalId());
        BusinessException.throwErrorIf(hospital == null,"医院不存在,请联系管理员");

        Supplier supplier =  supplierService.getById(entity.getSupplierId());
        BusinessException.throwErrorIf(supplier == null,"供应商不存在,请联系管理员");
        entity.setSupplierName(supplier.getName()).setHospitalName(hospital.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(MaterialApplicant entity) {
        if (entity.isNewRecord()) {
            entity.setCode(SerialUtils.generateCode(
                            SerialRuleConsts.BASE_MATERIAL_APPLICANT_CODE, SerialOwnerUtils.getSupplierOwner(entity.getSupplierId())))
                    .setStatus(MaterialApplicant.STATUS_UNSUBMIT);
        }
        super.saveOrUpdate(entity);
        fillData(entity);
        return true;
    }

    @Override
    public MaterialApplicant getById(Serializable id) {
        MaterialApplicant entity = super.getById(id);
        fillData(entity);
        return entity;
    }

    @Override
    public void saveBatchWithPass(List<MaterialApplicantAddBatchDto> applicantAddBatchDtoList) {
        List<String> spIdList = applicantAddBatchDtoList.stream().map(MaterialApplicantAddBatchDto::getSupplierId).distinct().collect(Collectors.toList());
        String hospitalId = applicantAddBatchDtoList.get(0).getHospitalId();

        Date now = DateUtils.now();
        List<String> codeList = SerialUtils.batchGenerateCode(
                SerialRuleConsts.BASE_MATERIAL_APPLICANT_CODE,
                SerialOwnerUtils.getHospitalOwner(hospitalId),
                spIdList.size()
        );

        MaterialApplicant applicant;
        List<MaterialApplicant> applicantList = new ArrayList<>();

        MaterialApplicantItem applicantItem;
        List<MaterialApplicantItem> applicantItemList = new ArrayList<>();
        int index = 0;
        Map<String,List<MaterialApplicantAddBatchDto>> addBySpId = applicantAddBatchDtoList.stream().collect(Collectors.groupingBy(MaterialApplicantAddBatchDto::getSupplierId));
        for(String supplierId : spIdList) {
            applicant = new MaterialApplicant();
            applicant.setHospitalId(hospitalId).setSupplierId(supplierId);
            applicant.setCode(codeList.get(index)).setRemark("物资系统推送自动创建");
            applicant.setGmtAudited(now).setAuditor("系统").setAuditedRemark("自动审核通过").setStatus(SupplierApplicant.STATUS_PASSED);
            applicant.setId(IdWorker.getIdStr());

            for(MaterialApplicantAddBatchDto batchDto : addBySpId.get(supplierId)) {
                applicantItem = new MaterialApplicantItem();
                applicantItem.setApplicantId(applicant.getId()).setMaterialId(batchDto.getMaterialId()).setMaterialSpecId(batchDto.getMaterialSpecId());
                applicantItemList.add(applicantItem);
            }
            index++;
            applicantList.add(applicant);
        }

        this.saveBatch(applicantList);
        materialApplicantItemService.saveBatch(applicantItemList);
    }


}
